/*
 * scheduler_o_1.h
 *
 *  Created on: 2011-5-19
 *      Author: chenl
 */

#ifndef SCHEDULER_O_1_H_
#define SCHEDULER_O_1_H_

#include "scheduler_o_n.h"
#include "processmgt.h"
#include "priorunqueue.h"
#include "os/sched.h"
#include "config.h"

#include <algorithm>

#define MAX_USER_RT_PRIO        100
#define MAX_RT_PRIO             MAX_USER_RT_PRIO
#define MAX_PRIO                (MAX_RT_PRIO + 40)
#define USER_PRIO(p)		((p)-MAX_RT_PRIO)
#define TASK_USER_PRIO(p)	USER_PRIO((p)->static_prio)
#define MAX_USER_PRIO		(USER_PRIO(MAX_PRIO))

#define HZ					(GET_PARAMCONFIG_INSTANCE().GetHZ())
#define MIN_TIMESLICE		std::max(5 * HZ / 1000, 1)
#define DEF_TIMESLICE		(100 * HZ / 1000)
#define SCALE_PRIO(x, prio) \
	std::max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO/2), MIN_TIMESLICE)


#define NICE_TO_PRIO(nice)	(MAX_RT_PRIO + (nice) + 20)
#define PRIO_TO_NICE(prio)	((prio) - MAX_RT_PRIO - 20)
#define TASK_NICE(p)		PRIO_TO_NICE((p)->static_prio)


class CScheduler_O_1: public CScheduler_O_N
{
public:
	CScheduler_O_1();
	virtual ~CScheduler_O_1();
public:
	virtual int32_t Initialize()
	{
		return S_OK;
	}
	virtual int32_t Uninitialize()
	{
		return S_OK;
	}
	virtual void schedule();
	virtual void scheduler_tick();

protected:
	inline unsigned int task_timeslice(struct task_struct *p)
	{
		if (p->static_prio < NICE_TO_PRIO(0))
			return SCALE_PRIO(DEF_TIMESLICE*4, p->static_prio);
		else
			return SCALE_PRIO(DEF_TIMESLICE, p->static_prio);
	}
	void recalc_task_prio(struct task_struct *p, unsigned long long now);
	int effective_prio(struct task_struct *p);
	inline void update_cpu_clock(struct task_struct *p, CPrioRunQueue* rq,
					    unsigned long long now)
	{
		unsigned long long last = std::max(p->timestamp, rq->timestamp_last_tick);
		p->sched_time += now - last;
	}

	void enqueue_task(CTask& task, CPrioRunQueue::RunQueue& queue)
	{
		logEngine.WriteLog(enmLogLevel_INFO, "enqueueing(0x%08x) task(pid=%d,prio=%d,static_prio=%d)",
				&queue, task.task.pid, task.task.prio, task.task.static_prio);
		queue.queue[task.task.prio].InsertTask(task);
		++queue.nr_active;
		SET_BIT(queue.bitmap[task.task.prio / 32], task.task.prio % 32);
		task.task.array = &queue;
	}
	void dequeue_task(CTask& task, CPrioRunQueue::RunQueue& queue)
	{
		logEngine.WriteLog(enmLogLevel_INFO, "dequeue(0x%08x) task(pid=%d,prio=%d,static_prio=%d)",
				&queue, task.task.pid, task.task.prio, task.task.static_prio);
		int32_t ret = queue.queue[task.task.prio].DeleteTask(task);
		assert(0 <= ret);
		--queue.nr_active;
		if (queue.queue[task.task.prio].IsEmtpy())
		{
			CLEAR_BIT(queue.bitmap[task.task.prio / 32], task.task.prio % 32);
			logEngine.WriteLog(enmLogLevel_INFO, "bit map cleared for task(pid=%d)", task.task.pid);
		}

	}
	void deactivate_task(CTask& task, CPrioRunQueue& queue)
	{
		--queue.nr_running;
		dequeue_task(task, *task.task.array);
		task.task.array = NULL;
	}

public:
	CPSThreadLog& logEngine;

};
#endif /* SCHEDULER_O_1_H_ */
